package org.redmaple.core.template.controller.web;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.redmaple.core.bean.PageData;
import org.redmaple.core.bean.ResponseResults;
import org.redmaple.core.retrieving.Sort;
import org.redmaple.core.support.Page;
import org.redmaple.core.support.PageHead;
import org.redmaple.core.template.dto.BaseDTO;
import org.redmaple.core.template.model.BaseModel;
import org.redmaple.core.template.service.IPageService;
import org.redmaple.core.util.Data7ViewerConvert;
import org.redmaple.core.util.ServletRequestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

/**
 * 控制器父类
 * 
 * @author Xiangyun
 *
 * @param <T>
 *            域模型
 * @param <X>
 *            视图模型
 */
@SuppressWarnings("all")
public abstract class BaseController<T extends BaseModel, X extends BaseDTO> {

	protected Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 域模型的class对象
	 */
	protected Class<T> domainModel;

	/**
	 * 视图模型的class对象
	 */
	protected Class<X> viewModel;

	/**
	 * 要注入的Service
	 */
	protected IPageService<T> service;

	/**
	 * 在构造函数中，初始化域模型和视图模型的class对象
	 */
	@SuppressWarnings("unchecked")
	public BaseController() {
		this.domainModel = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		this.viewModel = (Class<X>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[1];
		logger.debug("初始化成功 " + getClass().getName());
	}

	/**
	 * 获取查询列表页面的JSP页面路径，在具体类中返回一个路径常量即可
	 * 
	 * @return 查询列表页面的JSP页面路径
	 */
	public abstract String getQueryJspPath();

	/**
	 * 获取更新页面的JSP页面路径，在具体类中返回一个路径常量即可
	 * 
	 * @return 更新页面的JSP页面路径
	 */
	public abstract String getUpdateJspPath();

	/**
	 * 获取查询详细信息页面的JSP页面路径，在具体类中返回一个路径常量即可
	 * 
	 * @return 查询详细信息页面的JSP页面路径
	 */
	public abstract String getViewJspPath();

	/**
	 * 获取新建页面的JSP页面路径，在具体类中返回一个路径常量即可
	 * 
	 * @return 新建页面的JSP页面路径
	 */
	public abstract String getNewJspPath();

	/**
	 * 从requet中获取要删除的对象ID列表
	 * 
	 * @param request
	 *            HttpServletRequest请求对象
	 * @return 要删除的对象ID列表
	 */
	protected abstract List<String> deleteEntitiyIds(HttpServletRequest request);

	/**
	 * 设置Service对象。<br/>
	 * 这个方法要由具体类来实现，格式如下：
	 * 
	 * <br/>@Resource(name = "****")<br/>
	 * public void setService(IPageService&lt;T&gt; service){<br/>
	 * &emsp;this.service = service;<br/>
	 * }<br/>
	 * <br/>
	 *                其中****就是你要注入的Serivice对象
	 * 
	 * @param service
	 */
	public abstract void setService(IPageService<T> service);

	/**
	 * 获取列表页面查询列表数据时的检索信息的Map映射，没有分页要求
	 * 
	 * @param request
	 *            没有分页要求的HttpServletRequest请求对象
	 * @return 列表页面查询列表数据时的检索信息的Map映射
	 */
	protected abstract Map<String, Object> getQueryListFilterMap(
			HttpServletRequest request);

	/**
	 * 获取列表页面查询列表数据时的检索信息的Map映射，有分页要求
	 * 
	 * @param request
	 *            有分页要求的HttpServletRequest请求对象
	 * @return 列表页面查询列表数据时的检索信息的Map映射
	 */
	protected abstract Map<String, Object> getQueryPageFilterMap(
			HttpServletRequest request);

	/**
	 * 获取Serivice对象
	 * 
	 * @return
	 */
	public IPageService<T> getService() {
		return service;
	}

	/**
	 * 跳转到查询页面请求，只能用GET请求
	 * 
	 * @param model
	 *            Model对象
	 * @return 查询列表页面的JSP页面路径
	 */
	@RequestMapping(value = "query", method = RequestMethod.GET)
	public String queryPage(Model model) {
		openQueryPage(model);
		return getQueryJspPath();
	}

	/**
	 * 跳转到更新页面请求，只能用GET请求
	 * 
	 * @param id
	 *            要更新对象ID
	 * @param model
	 *            Model对象
	 * @return 查询列表页面的JSP页面路径
	 */
	@RequestMapping(value = "update/{id}", method = RequestMethod.GET)
	public String updatePage(@PathVariable("id") String id, Model model) {
		T object = service.findOne(id);
		X objectDTO = null;
		try {
			objectDTO = (X) viewModel.newInstance().convert(object);
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		openUpdatePage(objectDTO, model);
		return getUpdateJspPath();
	}

	/**
	 * 跳转到新建页面的请求，只能用GET请求
	 * 
	 * @param model
	 *            Model对象
	 * @return 新建页面的JSP页面路径
	 */
	@RequestMapping(value = "new", method = RequestMethod.GET)
	public String newPage(Model model) {
		openNewPage(model);
		return getNewJspPath();
	}

	/**
	 * 跳转到查看详细信息页面请求，只能用GET请求
	 * 
	 * @param id
	 *            要查看对象ID
	 * @param model
	 *            Model对象
	 * @return 查看详细信息页面的JSP页面路径
	 */
	@RequestMapping(value = "view/{id}", method = RequestMethod.GET)
	public String viewPage(@PathVariable("id") String id, Model model) {
		T object = service.findOne(id);
		X objectDTO = null;
		try {
			objectDTO = (X) viewModel.newInstance().convert(object);
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		openViewPage(objectDTO, model);
		return getViewJspPath();
	}

	/**
	 * 获取分页数据请求，只能用POST请求
	 * 
	 * @param request
	 *            有分页要求的HttpServletRequest请求对象
	 * @return 分页数据
	 */
	@RequestMapping(value = "getPageData", method = RequestMethod.POST)
	@ResponseBody
	public PageData<X> getPageData(HttpServletRequest request) {
		PageHead pageInfo = ServletRequestUtils.getPageInfo(request);
		Map<String, Object> filterPropertyMap = getQueryPageFilterMap(request);
		List<Sort> sortValues = ServletRequestUtils.getSortList(request);
		Page<T> page = service.findPageByCondition(filterPropertyMap,
				sortValues, pageInfo);
		return new PageData(page, domainModel);
	}

	/**
	 * 获取不分页数据请求，只能用POST请求
	 * 
	 * @param request
	 *            有分页要求的HttpServletRequest请求对象
	 * @return 列表数据
	 */
	@RequestMapping(value = "getListData", method = RequestMethod.POST)
	@ResponseBody
	public List<X> getListData(HttpServletRequest request) {
		List<X> listRet = new ArrayList<X>();
		Map<String, Object> filterPropertyMap = getQueryListFilterMap(request);
		List<Sort> sortValues = ServletRequestUtils.getSortList(request);
		List<T> list = service.findListByCondition(filterPropertyMap,
				sortValues);
		try {
			for (T model : list) {
				listRet.add((X) viewModel.newInstance().convert(model));
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return listRet;
	}

	/**
	 * 保存新建对象信息的请求，只能用POST请求
	 * 
	 * @param request HttpServletRequest请求对象
	 * @param object 视图模型对象信息
	 * @return ResponseResults对象，其中放置了操作结果及其其他相关信息
	 */
	@RequestMapping(value = "save", method = RequestMethod.POST)
	@ResponseBody
	public ResponseResults saveEntity(HttpServletRequest request, X object) {
		try {
			T model = domainModel.newInstance();
			model = Data7ViewerConvert.convert(object, model);
			model.setId(null);
			service.save(model);
			return saveSuccess();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return saveFailed();
	}

	/**
	 * 删除对象信息的请求，只能用POST请求
	 * 
	 * @param id 要删除的对象ID
	 * @return ResponseResults对象，其中放置了操作结果及其其他相关信息
	 */
	@RequestMapping(value = "delete/{id}", method = RequestMethod.POST)
	@ResponseBody
	public ResponseResults deleteEntity(@PathVariable("id") String id) {
		try {
			service.delete(id);
			return deleteSuccess();
		} catch (Exception e) {
			return deleteFailed();
		}
	}

	/**
	 * 批量删除对象信息的请求，只能用POST请求
	 * 
	 * @param request HttpServletRequest请求对象
	 * @return ResponseResults对象，其中放置了操作结果及其其他相关信息
	 */
	@RequestMapping(value = "deletes", method = RequestMethod.POST)
	@ResponseBody
	public ResponseResults deleteEntities(HttpServletRequest request) {
		try {
			List<String> ids = deleteEntitiyIds(request);
			service.deletes(ids);
			return deletesSuccess();
		} catch (Exception e) {
			return deletesFailed();
		}
	}

	/**
	 * 保存更新对象信息的请求，只能用POST请求
	 * 
	 * @param id 要更新的对象ID
	 * @param request HttpServletRequest请求对象
	 * @param object 视图模型对象信息
	 * @return ResponseResults对象，其中放置了操作结果及其其他相关信息
	 */
	@RequestMapping(value = "update", method = RequestMethod.POST)
	@ResponseBody
	public ResponseResults updateEntity(@PathVariable("id") String id,
			HttpServletRequest request, X object) {
		try {
			T model = domainModel.newInstance();
			model = Data7ViewerConvert.convert(object, model);
			model.setId(id);
			service.update(model);
			return updateSuccess();
		} catch (Exception e) {
			return updateFailed();
		}
	}

	/**
	 * 打开查询页面的其他操作
	 * 
	 * @param model Model对象
	 */
	public abstract void openQueryPage(Model model);

	/**
	 * 打开新建页面的其他操作
	 * 
	 * @param model Model对象
	 */
	public abstract void openNewPage(Model model);

	/**
	 * 打开更新界面的其他操作，一般要求要将objectDTO对象存入到model中
	 * 
	 * @param objectDTO 视图模型对象
	 * @param model Model对象
	 */
	public abstract void openUpdatePage(X objectDTO, Model model);

	/**
	 * 打开更新界面的其他操作，一般要求要将objectDTO对象存入到model中
	 * 
	 * @param objectDTO 视图模型对象
	 * @param model Model对象
	 */
	public abstract void openViewPage(X objectDTO, Model model);

	/**
	 * 保存新建对象成功后的响应信息，一般要设置result为true
	 * 
	 * @return ResponseResults对象信息
	 */
	public abstract ResponseResults saveSuccess();

	/**
	 * 保存新建对象失败后的响应信息，一般要设置result为true
	 * 
	 * @return ResponseResults对象信息
	 */
	public abstract ResponseResults saveFailed();

	/**
	 * 删除对象成功后的响应信息，一般要设置result为true
	 * 
	 * @return ResponseResults对象信息
	 */
	public abstract ResponseResults deleteSuccess();

	/**
	 * 删除对象失败后的响应信息，一般要设置result为true
	 * 
	 * @return ResponseResults对象信息
	 */
	public abstract ResponseResults deleteFailed();

	/**
	 * 批量删除对象成功后的响应信息，一般要设置result为true
	 * 
	 * @return ResponseResults对象信息
	 */
	public abstract ResponseResults deletesSuccess();

	/**
	 * 批量删除对象失败后的响应信息，一般要设置result为true
	 * 
	 * @return ResponseResults对象信息
	 */
	public abstract ResponseResults deletesFailed();

	/**
	 * 保存更新对象成功后的响应信息，一般要设置result为true
	 * 
	 * @return ResponseResults对象信息
	 */
	public abstract ResponseResults updateSuccess();

	/**
	 * 保存更新对象失败后的响应信息，一般要设置result为true
	 * 
	 * @return ResponseResults对象信息
	 */
	public abstract ResponseResults updateFailed();
}
